%token <string> VAR
%token AND OR XOR EQ NOT IMP
%token TRUE FALSE NONE BOTH
%token DEF FUNC COM SC BEGIN END
%token LPAREN RPAREN
%token EOF
%left EQ IMP        /* lowest precedence */
%left AND OR XOR
%left NOT
%start main             /* the entry point */
%type <Ast.prg> main
%%
main:
defs BEGIN expr END EOF
{ { Ast.defs = $1; Ast.main = $3 } }

defs:
|                       { [] }
| def defs              { $1 :: $2 }

pplist:
| LPAREN RPAREN         { [] }
| LPAREN plist RPAREN   { $2 }

plist:
| VAR                   { [ $1 ] }
| VAR COM plist         { $1 :: $3 }

def:
| DEF VAR EQ expr SC
{ Ast.VarDecl ($2,$4) }
| FUNC VAR pplist EQ expr SC
{ Ast.FunDecl ($2,$3,$5) }

eelist:
| LPAREN RPAREN         { [] }
| LPAREN elist RPAREN   { $2 }

elist:
| expr                  { $1 :: [] }
| expr COM elist        { $1 :: $3 }

expr:
| VAR                   { Ast.Var $1 }
| NONE                  { Ast.None }
| TRUE                  { Ast.True }
| FALSE                 { Ast.False }
| BOTH                  { Ast.Both }
| LPAREN expr RPAREN    { $2 }
| expr AND expr         { Ast.BOp ("&",$1,$3) }
| expr OR expr          { Ast.BOp ("|",$1,$3) }
| expr XOR expr         { Ast.BOp ("<>",$1,$3) }
| expr EQ expr          { Ast.BOp ("=",$1,$3) }
| expr IMP expr         { Ast.BOp ("=>",$1,$3) }
| NOT expr              { Ast.Not $2 }
| VAR eelist
      { Ast.Call ($1,$2) }
;
